﻿using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;

namespace daStaticAnalyser.Analysers
{
    using daStaticAnalyser.Analysers;
    using daStaticAnalyser;
    using daBase.Objects;
    using daBase.Analyser;
    using daSyntaxAnalyser;
    using daSyntaxAnalyser.SyntaxTree;

    [AnalyserDefaultSettings("Метрики Холстеда", "test", 0, "test")]
    class HolstedAnalyzator : BaseStaticAnalyser
    {
        bool VocSet, LenSet, VolSet, DiffSet, HeffSet;
        
        [Category("Особые")]
        [DisplayName("Словарь подпрограммы")]
        [Description("Если флаг не установлен, то метрика отсутствует в результатах анализа.")]
        public bool IsVocSet { get { return VocSet; } set { VocSet = value; } }

        [Category("Особые")]
        [DisplayName("Размер подпрограммы")]
        [Description("Если флаг не установлен, то метрика отсутствует в результатах анализа.")]
        public bool IsLenSet { get { return LenSet; } set { LenSet = value; } }

        [Category("Особые")]
        [DisplayName("Объём подпрограммы")]
        [Description("Если флаг не установлен, то метрика отсутствует в результатах анализа.")]
        public bool IsVolSet { get { return VolSet; } set { VolSet = value; } }

        [Category("Особые")]
        [DisplayName("Сложность подпрограммы")]
        [Description("Если флаг не установлен, то метрика отсутствует в результатах анализа.")]
        public bool IsDiffSet { get { return DiffSet; } set { DiffSet = value; } }

        [Category("Особые")]
        [DisplayName("Усилия программиста")]
        [Description("Если флаг не установлен, то метрика отсутствует в результатах анализа.")]
        public bool IsHeffSet { get { return HeffSet; } set { HeffSet = value; } }
        
        List<String> UOprtr, 
                     UOprnd;
        int NOprtr,
            NOprnd;

        protected override void DoAnalyse(SyntaxTreeArgs e)
        {
            if (e.Element is OuterMethodElement)
            {
                var OuterMethod = e.Element as OuterMethodElement;

                UOprtr = new List<string>();
                UOprnd = new List<string>();
                NOprtr = 0;
                NOprnd = 0;

                GetData(OuterMethod.Body);

                int NUOprtr = UOprtr.Count,
                    NUOprnd = UOprnd.Count;
                int HPVoc = NUOprtr + NUOprnd,//Словарь подпрограммы
                    HPLen = NOprtr + NOprnd;//Длина подпрограммы
                double HPVol = HPLen * Math.Log(2, HPVoc);//Объём подпрограммы(бит)
                double HDiff;//Сложность подпрограммы
                if (NUOprnd == 0) HDiff = 0; else HDiff = (NUOprtr/2)*(NOprnd/NUOprnd);                
                double HEff = HDiff * HPVol;//Усилия программиста

                String MethodName;
                if (OuterMethod.Header is OuterProcedureHeadElement)
                {
                    MethodName = (OuterMethod.Header as OuterProcedureHeadElement).Id.Text;
                }
                else
                {
                    MethodName = (OuterMethod.Header as OuterFunctionHeadElement).Id.Text;
                }

                if (VocSet)
                {
                    AddMetric("Словарь подпрограммы",
                                Convert.ToSingle(HPVoc),
                                MethodName,
                                OuterMethod.StartInfo.File,
                                OuterMethod.StartInfo.Line);
                }
                if (LenSet)
                {
                    AddMetric("Длина подпрограммы",
                                Convert.ToSingle(HPLen),
                                MethodName,
                                OuterMethod.StartInfo.File,
                                OuterMethod.StartInfo.Line);
                }
                if (VolSet)
                {
                    AddMetric("Объём подпрограммы(бит)",
                                Convert.ToSingle(HPVol),
                                MethodName,
                                OuterMethod.StartInfo.File,
                                OuterMethod.StartInfo.Line);
                }
                if (DiffSet)
                {
                    AddMetric("Сложность подпрограммы",
                                Convert.ToSingle(HDiff),
                                MethodName,
                                OuterMethod.StartInfo.File,
                                OuterMethod.StartInfo.Line);
                }
                if (HeffSet)
                {
                    AddMetric("Усилия программиста",
                                Convert.ToSingle(HEff),
                                MethodName,
                                OuterMethod.StartInfo.File,
                                OuterMethod.StartInfo.Line);
                }
 
            }
        }

        private void GetData(ISyntaxTreeElement Element)
        {
            if (Element == null)
                return;

            if (Element is CaseBlockStatementElement)
            {
                NOprtr++;
                if (!UOprtr.Contains("case")) UOprtr.Add("case");
            }
            else if (Element is TryStatementElement)
            {
                NOprtr++;
                if (!UOprtr.Contains("try")) UOprtr.Add("try");
            }
            else if (Element is RepeatStatementElement)
            {
                NOprtr++;
                if (!UOprtr.Contains("repeat")) UOprtr.Add("repeat");
            }
            else if (Element is ExceptOnStatementElement)
            {
                NOprtr++;
                if (!UOprtr.Contains("except")) UOprtr.Add("except");
            }
            else if (Element is ForStatementElement)
            {
                NOprtr++;
                if (!UOprtr.Contains("for")) UOprtr.Add("for");
            }
            else if (Element is TestStatementElement)
            {
                NOprtr++;
                if (!UOprtr.Contains("if")) UOprtr.Add("if");
            }
            else if (Element is WhileStatementElement)
            {
                NOprtr++;
                if (!UOprtr.Contains("while")) UOprtr.Add("while");
            }
            else if (Element is AssignmentElement)
            {
                NOprtr++;
                if (!UOprtr.Contains(":=")) UOprtr.Add(":=");
            }
            else if (Element is StandartVariableExpressionElement)
            {
                String temp = Element.ToString();
                if (temp.Contains("("))
                {
                    NOprtr++;
                    int pos = temp.IndexOf('(');
                    String temp2 = temp.Substring(0,pos);
                    if (!UOprtr.Contains(temp2)) UOprtr.Add(temp2);
                }
                else
                {
                    NOprnd++;
                    if (!UOprnd.Contains(temp)) UOprnd.Add(temp);
                }
            }
            else if (Element is BinaryExpressionElement)
            {
                NOprtr++;
                BinaryExpressionElement temp = (Element as BinaryExpressionElement);
                if (!UOprtr.Contains(temp.Type.Text)) UOprtr.Add(temp.Type.Text);
            }
            else if (Element is ConstExpressionElement)
            {
                NOprnd++;
                if (!UOprnd.Contains(Element.StartInfo.Text)) UOprnd.Add(Element.StartInfo.Text);
            }

            foreach (ISyntaxTreeElement element in Element)
            {
                GetData(element);
            }
        }
    }
}
